package com.zlc.common.util;

import com.github.xiaoymin.swaggerbootstrapui.util.CommonUtils;
import com.zlc.common.common.entity.BaseEntity;
import com.zlc.common.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author zl
 */
@Slf4j
public class BeanCopyUtils {

    private BeanCopyUtils(){}
    /**
     * 单个对象属性拷贝
     * 
     * @param source
     *            源对象
     * @param clazz
     *            目标对象Class
     * @param <T>
     *            目标对象类型
     * @param <M>
     *            源对象类型
     * @return 目标对象
     */
    public static <T, M> T copy(M source, Class<T> clazz) {
        if (Objects.isNull(source) || Objects.isNull(clazz)) {
            throw new IllegalArgumentException("当前传入源数据为空,请联系1890!");
        }
        return copyProperties(source, clazz, null);
    }


    public static <T, M> T copyAndInit(M source, Class<T> clazz) {
        T copy = copyObj(source, clazz);
        if (copy instanceof BaseEntity) {
            initEmpty((BaseEntity)copy);
        }
        return copy;
    }

    /**
     * 查询操作时初始值致为空
     *
     * @param baseEntity
     */
    public static  void initEmpty(BaseEntity baseEntity) {
        try {
            // 清除元数据id 创建人 创建时间 版本信息
            baseEntity.setId(null);
            baseEntity.setCreateUser(null);
            baseEntity.setCreateTime(null);
            baseEntity.setVersion(0);
            baseEntity.setDeleteFlag(Boolean.FALSE);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException("初始化实体失败");
        }
    }

    /**
     * 单个对象属性拷贝
     * 
     * @param source
     *            源对象
     * @param clazz
     *            目标对象Class
     * @param copier
     *            copier
     * @param <T>
     *            目标对象类型
     * @param <M>
     *            源对象类型
     * @return 目标对象
     */
    private static <T, M> T copyProperties(M source, Class<T> clazz, BeanCopier copier) {
        if (null == copier) {
            copier = BeanCopier.create(source.getClass(), clazz, false);
        }
        T t = null;
        try {
            t = clazz.newInstance();
            copier.copy(source, t, null);
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return t;
    }




    /**
     * 浅层复制
     */
    public static  <T>List<T> copyObjList(Object objs,Class<T> clazz){
        if(ObjectUtils.isEmpty(objs)){
            return new ArrayList<>();
        }
        List<T> rets = new ArrayList<>();
        if(objs instanceof List){
            List<?> list = (List<?>) objs;
            for(Object obj : list){
                T t = copyObj(obj,clazz);
                rets.add(t);
            }
        }

        return rets;
    }

    /**
     * 复制对象，浅层复制
     * @param obj  被复制对象
     * @param copy 返回对象
     * @param <T>  复制类型
     */
    public static <T>T copyObj(Object obj,Class<T> copy){
        if(ObjectUtils.isEmpty(obj)){
            return null;
        }
        try {

            List<Field> fields = getFields(obj.getClass(),new ArrayList<>());
            T t = copy.newInstance();
            List<Field> copyFields = getFields(copy,new ArrayList<>());
            for (Field field : fields) {
                field.setAccessible(true);
                Field copyField = copyFields.stream().filter(f->f.getName().equals(field.getName())).findFirst().orElse(null);
                if(copyField == null){
                    continue;
                }
                if(!Modifier.isFinal(copyField.getModifiers())) {
                    copyField.setAccessible(true);
                    if(field.get(obj) != null) {
                        copyField.set(t, field.get(obj));
                    }
                }
            }
            return t;
        }catch (Exception e){
            log.error(e.getMessage(),e);
            throw new BusinessException("copy error "+e.getMessage());
        }
    }


    private static List<Field>  getFields(Class<?> copy,List<Field> fields){
        fields.addAll(Arrays.asList(copy.getDeclaredFields()));
        if(copy.getSuperclass() != Object.class){
            Class<?> superCopy = copy.getSuperclass();
            getFields(superCopy,fields);
            return fields;
        }else{
            return fields;
        }
    }

    public static <T>T copyObjValueToObj(T from ,T to){
        try {

            List<Field> fromCopyFields = getFields(from.getClass(),new ArrayList<>());
            List<Field> toCopyFields = getFields(to.getClass(),new ArrayList<>());
            for (Field field : fromCopyFields) {
                field.setAccessible(true);
                Field copyField = toCopyFields.stream().filter(f->f.getName().equals(field.getName())).findFirst().orElse(null);
                if(copyField == null){
                    continue;
                }
                if(!Modifier.isFinal(copyField.getModifiers())) {
                    copyField.setAccessible(true);
                    if(field.get(from) != null) {
                        copyField.set(to, field.get(from));
                    }
                }
            }
            return to;
        }catch (Exception e){
            log.error(e.getMessage(),e);
            return null;
        }
    }

    public static void trimObject(Object obj){
        List<Field> fields = getFields(obj.getClass(),new ArrayList<>());
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object o = field.get(obj);
                if(o instanceof CharSequence){
                    field.set(obj,String.valueOf(o).trim());
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * obj 字段为空 fCopy同字段不为空，则赋值fCopy同字段值到obj
     */
    public static <T>T copyObjIsNull(Object obj,Object fCopy){
        try {
            List<Field> fields = getFields(obj.getClass(), new ArrayList<>());
            List<Field> copyFields = getFields(fCopy.getClass(), new ArrayList<>());
            for (Field field : fields) {
                field.setAccessible(true);
                Field copyField = copyFields.stream().filter(f -> f.getName().equals(field.getName())).findFirst().orElse(null);
                if (copyField == null) {
                    continue;
                }
                if (!Modifier.isFinal(copyField.getModifiers())) {
                    copyField.setAccessible(true);
                    if (field.get(obj) == null && copyField.get(fCopy) != null) {
                        field.set(obj, copyField.get(fCopy));
                    }
                }
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
            e.printStackTrace();
            return null;
        }
        return null;
    }
}